package bio_nio_aio.bio.com_Demo.wechatroom;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List;

public class ChatServer {

	private List<Client> clients = new ArrayList<>();

	/**
	 * 功能：启动ChatSever
	 *
	 * @param args
	 */
	public static void main(String[] args) {
		new ChatServer().init();
	}

	/**
	 * 功能：对chatserver初始化
	 */
	private void init() {
		System.out.println("服务器已开启");

		ServerSocket ss = null;
		Socket socket = null;
		try {
			ss = new ServerSocket(8888);
		} catch (BindException e) {
			System.out.println("端口已被占用");
			e.printStackTrace();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		try {
			Client client = null;
			while (true) {
				//开启服务器等待功能 (这个等待功能要一直开启)
				socket = ss.accept();
				System.out.println("客户驾到");
				client = new Client(socket);
				//将新来的客户加入到集合里
				clients.add(client);
				//开启一个新的线程 ，将这个交给另外一个线程去处理
				new Thread(client).start();
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private class Client implements Runnable {
		private Socket socket = null;
		InputStream in = null;
		DataInputStream din = null;
		OutputStream out = null;
		DataOutputStream dos = null;
		boolean flag = true;
		//构造方法用来传参(这里在传入参数之后会进行初始化的操作)
		public Client(Socket socket) {
			this.socket = socket;
			try {
				in = socket.getInputStream();
				din = new DataInputStream(in);
			} catch (IOException e) {
				System.out.println("接受消息失败");
				e.printStackTrace();
			}
		}

		//线程开启之后就会跳到这个方法执行
		public void run() {
			//定义一个变量用来储存信息
			String message;
			try {
				while (flag) {
					// 读取一个用户发来的信息
					message = din.readUTF();
					// 将信息发送给所有的客户端
					forwordToAllClients(message);
				}
			} catch (SocketException e) {
				flag = false;
				System.out.println("客户下线");
				//从集合里面移除次客户
				clients.remove(this);
				e.printStackTrace();
			} catch (EOFException e) {
				flag = false;
				System.out.println("客户下线");
				clients.remove(this);
				e.printStackTrace();
			} catch (IOException e) {
				flag = false;
				System.out.println("接受消息失败");
				clients.remove(this);
				e.printStackTrace();
			}

			if (din != null) {
				try {
					din.close();
				} catch (IOException e) {
					System.out.println("din关闭失败");
					e.printStackTrace();
				}
			}
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					System.out.println("din关闭失败");
					e.printStackTrace();
				}
			}
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
					System.out.println("din关闭失败");
					e.printStackTrace();
				}
			}
		}

		/**
		 * 功能：转发给所有客户端
		 *
		 * @param message
		 * @throws IOException
		 */
		private void forwordToAllClients(String message) throws IOException {
			//通过遍历将信息发送个所有的用户
			for (Client c : clients) {
				//注意这里发送的用户不包括提供消息的那个用户（判断是否为同一个对象比较的是内存地址的值是否相等）
				if (c != this) {
					//获取当前用户的socket
					out = c.socket.getOutputStream();
					dos = new DataOutputStream(out);
					forwordToClient(message);
				}
			}
		}

		/**
		 * 功能：发送给一个客户端
		 *
		 * @throws IOException
		 */
		private void forwordToClient(String message) throws IOException {
			//将信息发送
			dos.writeUTF(message);
			dos.flush();
			System.out.println("转发成功！");
		}

	}
}